/*
Copyright (C) 2016  Marien Raat

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "ball.h"

#include "config.h"

void Ball::initialize(b2World *world, float radius)
{
    ballCircle.setRadius(radius);
    ballCircle.setFillColor(sf::Color(255, 0, 0));
    ballCircle.setOrigin(radius, radius);

    this->world = world;
    b2BodyDef bodyDef;
    bodyDef.linearDamping = 0.5f;
    bodyDef.angularDamping = 0.5f;
    bodyDef.type = b2_dynamicBody;
    body = world->CreateBody(&bodyDef);

    b2CircleShape circleShape;
    circleShape.m_radius = radius / SCALE_F;
    b2FixtureDef fixtureDef;
    fixtureDef.shape = &circleShape;
    fixtureDef.density = 0.2f;
    fixtureDef.friction = 1.0f;
    fixtureDef.restitution = 0.8f;
    body->CreateFixture(&fixtureDef);
}

void Ball::update()
{
    float x = body->GetPosition().x * SCALE_F;
    if (x < -BALL_RADIUS) {
        reset();
    }
    if (x > FIELD_SIZE.x + BALL_RADIUS) {
        reset();
    }
}

void Ball::draw(sf::RenderTarget *target)
{
    ballCircle.setPosition(getPosition());
    ballCircle.setRotation(getRotation());
    target->draw(ballCircle);
}

void Ball::setPosition(sf::Vector2f position)
{ 
    position /= (float) SCALE;
    b2Vec2 bodyPosition(position.x, position.y);
    body->SetTransform(bodyPosition, body->GetAngle());
}

sf::Vector2f Ball::getPosition()
{
    b2Vec2 bodyPosition = body->GetPosition();
    return sf::Vector2f(SCALE * bodyPosition.x,
                        SCALE * bodyPosition.y);
}

void Ball::setRotation(float rotationInDegrees)
{
    body->SetTransform(body->GetPosition(),
                       DEG_TO_RAD * rotationInDegrees);
}

float Ball::getRotation()
{
    return RAD_TO_DEG * body->GetAngle();
}

void Ball::reset()
{
    setPosition(FIELD_SIZE / 2.0f);
    setRotation(0);
    body->SetLinearVelocity(b2Vec2(0, 0));
    body->SetAngularVelocity(0);
}

sf::Packet &operator <<(sf::Packet &packet, Ball &ball)
{
    sf::Vector2f ballPosition = ball.getPosition();
    b2Vec2 linearVelocity = ball.body->GetLinearVelocity();
    packet << ballPosition.x << ballPosition.y << ball.getRotation()
           << linearVelocity.x << linearVelocity.y
           << ball.body->GetAngularVelocity();
}

sf::Packet &operator >>(sf::Packet &packet, Ball &ball)
{
    sf::Vector2f position;
    float rotation;
    b2Vec2 linearVelocity;
    float angularVelocity;
    packet >> position.x >> position.y >> rotation >> linearVelocity.x
           >> linearVelocity.y >> angularVelocity;
    ball.setPosition(position);
    ball.setRotation(rotation);
    ball.body->SetLinearVelocity(linearVelocity);
    ball.body->SetAngularVelocity(angularVelocity);
}
